package com.alks.function.service.impl.stockdept.pcfactorystockquery;

import com.alks.common.aop.AutoPageAop;
import com.alks.common.data.dto.SysUserTokenDTO;
import com.alks.common.data.thread.UserIdThread;
import com.alks.common.service.RedisService;
import com.alks.common.utils.beanutils.ArrayUtils;
import com.alks.common.utils.beanutils.BeanUtil;
import com.alks.common.utils.excelUtils.ExcelUtils;
import com.alks.common.utils.stringUtils.ZStringUtils;
import com.alks.entity.data.entity.*;
import com.alks.entity.data.enums.CompanyEnum;
import com.alks.entity.data.response.ResponseInfo;
import com.alks.entity.exception.ServiceErrorException;
import com.alks.function.data.dto.PcMtlCheckFinReq;
import com.alks.function.data.dto.SurfaceInMaterialReq;
import com.alks.function.data.dto.stockdept.pcfactorystockwork.PurSentDto;
import com.alks.function.data.dto.stockdept.pcfactorystockwork.PurUnSentDto;
import com.alks.function.data.request.stockdept.pcfactorystockwork.*;
import com.alks.function.data.vo.controller.stockdept.HgMtlRelationVo;
import com.alks.function.data.vo.stock.MtlAccVo;
import com.alks.function.mapper.MpPurDisMapper;
import com.alks.function.mapper.chengKong.PcLotHeadMapper;
import com.alks.function.mapper.common.BackMapper;
import com.alks.function.mapper.pcfactorywork.PcSupplementMtlMapper;
import com.alks.function.mapper.stockdept.pcfactorystockquery.*;
import com.alks.function.service.stockdept.pcfactorystockquery.IHgMtlService;
import com.alks.function.service.stockdept.pcfactorystockquery.IPcMtlCheckService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.Page;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.support.atomic.RedisAtomicInteger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.alks.common.utils.beanutils.BeanUtil.copyList;
import static com.alks.entity.data.enums.RedisFormatEnum.PUT_STOCK_LENGTH;
import static com.alks.entity.data.enums.ResultCodeEnum.*;

/**
 * <p>
 * 材料暂收表 服务实现类
 * </p>
 *
 * @author ms
 * @since 2023-08-23
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class PcMtlCheckServiceImpl implements IPcMtlCheckService {
    private final MpPurDisMapper disMapper;
    private final SD_SQ_PcMtlCheckMapper checkMapper;
    private final YfMtlTypeNewMapper typeMapper;
    private final BackMapper backMapper;
    private final SD_SQ_PcMtlAccMapper mtlAccMapper;
    private final SD_SQ_PcMtlAccPackMapper mtlAccPackMapper;
    private final SD_SQ_PcMtlAccPartMapper mtlAccPartMapper;
    private final PcSupplementMtlMapper suppMtlMapper;
    private final IHgMtlService hgMtlService;
    private final RedisService redis;

    @Value("${spring.profiles.active}")
    private String env;

    @Override
    @AutoPageAop
    public ResponseInfo getPurUnSentQuery(MpPurDisRequest request, int i) {
        String companyId = UserIdThread.get().getCompanyId();
        /*获取数据*/
        List<PurUnSentDto> unSentDtos = new ArrayList<>();
        Map<String, BigDecimal> sum = new HashMap<>();
        switch (i) {
            case 0:
                unSentDtos = checkMapper.getPurUnSentQuery(request, companyId);
                sum = checkMapper.getUnSentSumQuery(request, companyId);
                break;
            case 1:
//                Set<String> auxList = getAuxMtlList();
                /*获取材料数据*/
                unSentDtos = suppMtlMapper.getPurSpUnSentQuery(request, companyId);
                /*获取辅料类型*/
                sum = suppMtlMapper.getSpUnSentSumQuery(request, companyId);
                break;
            default:
                break;
        }
        if (ArrayUtils.isEmpyt(unSentDtos)) {
            return ResponseInfo.ok();
        }
        // 补充海关编码
        if ("test".equals(env)||"rypro".equals(env)){
            for (PurUnSentDto dto : unSentDtos) {
                HgMtlRelation mtlRelation = new HgMtlRelation().setMtlNo(dto.getMtlNo())
                        .setMtlName(dto.getMtlName())
                        .setMtlSpec(dto.getMtlSpec())
                        .setMtlColor(dto.getMtlColor())
                        .setMtlUnit(dto.getMtlUnit());
                HgMtlRelationVo vo = hgMtlService.detailQueryByMtl(mtlRelation);
                if(vo!=null) {
                    dto.setMtlNoHg(vo.getMtlNoHg());
                    dto.setHgId(vo.getHgId());
                }
            }
        }

        /*数据封装*/
        Map<String, Object> map = new HashMap<>(4);
        if (!request.getPageNum().equals(-1) && !request.getPageSize().equals(-1)) {
            Page<PurUnSentDto> page = (Page<PurUnSentDto>) unSentDtos;
            map.put("total", page.getTotal());
        }
        map.put("dtos", unSentDtos);
        map.put("unsentSum", sum.get("unsentSum"));
        map.put("qtySum", sum.get("qtySum"));
        return ResponseInfo.ok(map);
    }

    private Set<String> getAuxMtlList() {
        return typeMapper.auxMtlTypeQuery();
    }

    @Override
    @AutoPageAop
    public ResponseInfo getPurSentQuery(MpPurDisRequest request, int i) {
        String companyId = UserIdThread.get().getCompanyId();
        /*选择输出类型*/
        request.setTypeFlag(i);
        /*获取数据*/
        List<PurSentDto> sendDto = checkMapper.getPurSentQuery(request, companyId);
        if (sendDto.isEmpty()){
            return ResponseInfo.ok();
        }

        // 补充海关数据
        if ("test".equals(env)||"rypro".equals(env)){
            for (PurSentDto dto : sendDto) {
                HgMtlRelation mtlRelation = new HgMtlRelation().setMtlNo(dto.getMtlNo())
                        .setMtlName(dto.getMtlName())
                        .setMtlSpec(dto.getMtlSpec())
                        .setMtlColor(dto.getMtlColor())
                        .setMtlUnit(dto.getMtlUnit());
                HgMtlRelationVo vo = hgMtlService.detailQueryByMtl(mtlRelation);
                if(vo!=null) {
                    dto.setMtlNoHg(vo.getMtlNoHg());
                    dto.setMtlNameEng(vo.getMtlNameEng());
                }
            }
        }

        Page<PurSentDto> page = (Page<PurSentDto>) sendDto;
        /*求和*/
        Float sendSum = checkMapper.getSentSumQuery(request, companyId);
//        double sendSum = 0;
//        for (PurSentDto dto : sendDto) {
//            sendSum += dto.getSendQty();
//        }
        /*数据封装*/
        Map<String, Object> map = new HashMap<>(3);
        map.put("dtos", sendDto);
        map.put("total", page.getTotal());
        map.put("sendSum", sendSum);
        return ResponseInfo.ok(map);
    }

    @Override
    public ResponseInfo sentMtlTypeQuery() {
        /*查询数据*/
        List<Map<String, String>> head = checkMapper.mtlTypeHeadQuery(UserIdThread.get().getUserName());
        List<Map<String, String>> user = checkMapper.mtlTypeUserQuery(UserIdThread.get().getUserName());
        /*封装结果*/
        Map map = new HashMap();
        map.put("head", head);
        map.put("user", user);
        return ResponseInfo.ok(map);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseInfo purSentAdd(List<AddPurSendRequest> request, String vendorNo, String sendNo, int slipType) {
        SysUserTokenDTO dto = UserIdThread.get();
        String companyId = dto.getCompanyId();
        if (StringUtils.isBlank(vendorNo)) {
            return ResponseInfo.error("未填入厂商名称", LOGIN_CONFIG_IS_NULL.getCode());
        }
        if (ArrayUtils.isEmpyt(request)) {
            throw new ServiceErrorException("请选择暂收数据");
        }
        SdVendor sdVendor = backMapper.getVendorNameByNo(vendorNo, companyId);
        if (sdVendor == null || StringUtils.isBlank(sdVendor.getVendorAbbr())) {
            throw new ServiceErrorException("厂商不存在");
        }
        String vendorName = sdVendor.getVendorAbbr();
        /*需求更改为没有输入则提示*/
        if (StringUtils.isBlank(sendNo)) {
            return ResponseInfo.error("未写入订购单号", LOGIN_CONFIG_IS_NULL.getCode());
        }
        List<PcMtlCheck> checks = new ArrayList<>();
        if (slipType == 0) {
            /*材料暂收部分数据处理*/
            mtlSent(request, companyId, checks);
        } else if (slipType == 1) {
            /*初始数据处理*/
//            for (AddPurSendRequest sentRequest : request) {
//                /*没有输入数据则报错*/
//                if (sentRequest.getSendQty() == null || sentRequest.getSendQty() <= 0) {
//                    return ResponseInfo.error("暂入数量不能为空或小于0", LOGIN_CONFIG_IS_NULL.getCode());
//                }
//                /*对补料暂收进行数据检验*/
//                LambdaQueryWrapper<PcSupplementMtl> wrapper = new LambdaQueryWrapper<PcSupplementMtl>()
//                        .select(PcSupplementMtl::getActQty)
//                        .eq(PcSupplementMtl::getSlipNo, sentRequest.getPurNo())
//                        .eq(PcSupplementMtl::getMtlNo, sentRequest.getMtlNo())
//                        .eq(PcSupplementMtl::getCompanyId, companyId)
//                        .last("LIMIT 1");
//                PcSupplementMtl mtl = suppMtlMapper.selectOne(wrapper);
//                if (mtl == null) {
//                    return ResponseInfo.error("暂收数据不存在", LOGIN_CONFIG_IS_NULL.getCode());
//                }
//                if (sentRequest.getSendQty() > sentRequest.getUnSendQty()) {
//                    return ResponseInfo.error("暂收数量不能大于未发数量", LOGIN_CONFIG_IS_NULL.getCode());
//                }
//                checks = copyList(request, PcMtlCheck.class);
//            }
            checks = getSuppMtlCheck(request, companyId);
        }
        for (PcMtlCheck check : checks) {
            String slipTypeName = check.getSlipType();
            if (StringUtils.isBlank(slipTypeName)) {
                slipTypeName = slipType == 0 ? "正单" : "补料";
            }
            LocalDateTime sendDate = check.getSendDate() == null ? LocalDate.now().atStartOfDay() : check.getSendDate();
            /*写入数据*/
            check.setCompanyId(companyId);
            check.setSendDate(sendDate);
            check.setSysDate(LocalDateTime.now());
            check.setSysUser(dto.getUserName());
            check.setVendorNo(vendorNo);
            check.setVendorName(vendorName);
            check.setSendNo(sendNo);
            check.setSlipType(slipTypeName);
            check.setLotDetail(check.getPurLot());
            /*写入数量*/
//            check.setSendQty(request.stream()
//                    .filter(a -> a != null &&
//                            a.getPurNo() != null && a.getPurNo().equals(check.getPurNo()) &&
//                            a.getPurLot() != null && a.getPurLot().equals(check.getPurLot()) &&
//                            a.getReqNo() != null && a.getReqNo().equals(check.getReqNo()) &&
//                            a.getMtlNo() != null && a.getMtlNo().equals(check.getMtlNo()))
//                    .findFirst()
//                    .map(a -> BigDecimal.valueOf(a.getSendQty()))
//                    .orElse(BigDecimal.ZERO));
            /*找出厂商名称*/
        }
        /*处理送货单号*/
        checkMapper.purSentAdd(checks);

        // 如果存在海关编码则录入关联表
        if ("test".equals(env)|| "rypro".equals(env)) {
            request.stream().filter(a->a.getHgId()!=null).forEach(a->{
                HgMtlRelation mtlRelation = new HgMtlRelation()
                        .setMtlColor(a.getMtlColor())
                        .setMtlNo(a.getMtlNo())
                        .setMtlName(a.getMtlName())
                        .setMtlSpec(a.getMtlSpec())
                        .setMtlUnit(a.getMtlUnit())
                        .setHgId(a.getHgId());
                hgMtlService.detailAdd(mtlRelation);
            });
        }
        return ResponseInfo.ok("暂收成功");
    }

    /**
     * 获取补单暂收数据
     */
    private @NotNull List<PcMtlCheck> getSuppMtlCheck(List<AddPurSendRequest> request, String companyId) {
        List<PcMtlCheck> checks;
        /*获取待入库数量*/
        Map<String, Double> toSendQtyMap = request.stream()
                .collect(Collectors.toMap(a -> a.getMtlNo() + "_" + a.getPurNo(),
                        a -> {
                            double sendQty = a.getSendQty() == null ? 0 : a.getSendQty();
                            double overQty = a.getOverQty() == null ? 0 : a.getOverQty();
                            return sendQty + overQty;
                        }));
        Map<String, Double> sendQtyMap = request.stream()
                .collect(Collectors.toMap(a -> a.getMtlNo() + "_" + a.getPurNo(),
                        AddPurSendRequest::getSendQty));
        Map<String, Double> minusQtyMap = request.stream()
                .filter(a -> a.getMinusQty() != null)
                .collect(Collectors.toMap(a -> a.getMtlNo() + "_" + a.getPurNo(),
                        AddPurSendRequest::getMinusQty));
        /*获取待入库数据*/
        checks = suppMtlMapper.getPurSentQuery(request, companyId);
        List<PcMtlCheck> minusCheckList = new ArrayList<>();
        for (PcMtlCheck check : checks) {
            String key = check.getMtlNo() + "_" + check.getPurNo();
            /*获取已入库数量*/
            LambdaQueryWrapper<PcMtlCheck> chekcWrapper = new LambdaQueryWrapper<PcMtlCheck>()
                    .eq(PcMtlCheck::getPurNo, check.getPurNo())
                    .eq(PcMtlCheck::getPurLot, check.getPurLot())
                    .eq(PcMtlCheck::getMtlName, check.getMtlName())
                    .eq(StringUtils.isNotBlank(check.getMtlColor()), PcMtlCheck::getMtlColor, check.getMtlColor())
                    .isNull(StringUtils.isBlank(check.getMtlColor()), PcMtlCheck::getMtlColor)
                    .eq(StringUtils.isNotBlank(check.getMtlUnit()), PcMtlCheck::getMtlUnit, check.getMtlUnit())
                    .isNull(StringUtils.isBlank(check.getMtlUnit()), PcMtlCheck::getMtlUnit)
                    .eq(StringUtils.isNotBlank(check.getMtlSpec()), PcMtlCheck::getMtlSpec, check.getMtlSpec())
                    .isNull(StringUtils.isBlank(check.getMtlSpec()), PcMtlCheck::getMtlSpec)
                    .eq(PcMtlCheck::getCompanyId, companyId);
            List<PcMtlCheck> mtlChecks = checkMapper.selectList(chekcWrapper);
            BigDecimal sendQty = BigDecimal.ZERO;
            if (ArrayUtils.isNoEmpyt(mtlChecks)) {
                sendQty = mtlChecks.stream()
                        .map(PcMtlCheck::getSendQty)
                        .filter(Objects::nonNull)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
            }
            /*判断数量限制*/
            Double a = sendQtyMap.get(key);
            BigDecimal sendQty2 = a == null ? BigDecimal.ZERO : BigDecimal.valueOf(a);
            Double b = toSendQtyMap.get(key);
            BigDecimal toSendQty = b == null ? BigDecimal.ZERO : BigDecimal.valueOf(b);
            BigDecimal allSendQty = sendQty2.add(sendQty);
            if (check.getSendQty().compareTo(allSendQty) < 0) {
                throw new ServiceErrorException("超出暂收数量限制");
            }
            /*区分正单多购入库*/
            check.setSendQty(toSendQty);
            check.setSlipType("补料");

            if (minusQtyMap.get(key) != null && minusQtyMap.get(key) > 0) {
                PcMtlCheck check1 = BeanUtil.copyBean(check, PcMtlCheck.class);
                check1.setSendQty(BigDecimal.valueOf(minusQtyMap.get(key)));
                check1.setSlipType("多购");
                minusCheckList.add(check1);
            }
        }
        checks.addAll(minusCheckList);
        return checks;
    }

    /**
     * 材料暂收数据
     */
    private void mtlSent(List<AddPurSendRequest> request, String companyId, List<PcMtlCheck> checks) {
        /*面材暂收*/
        Set<Integer> idSet = request.stream()
                .map(AddPurSendRequest::getId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        if (idSet.size() != request.size()) {
            log.error("\n错误接口：purSentAdd\n错误原因：ID数量异常\n暂收入参：{}", request);
            throw new ServiceErrorException("数据异常:重复ID");
        }
        LambdaQueryWrapper<MpPurDis> disWrapper = new LambdaQueryWrapper<MpPurDis>()
                .in(MpPurDis::getId, idSet)
                .eq(MpPurDis::getCompanyId, companyId);
        List<MpPurDis> disList = disMapper.selectList(disWrapper);
        if (disList.size() != idSet.size()) {
            log.error("\n错误接口：purSentAdd\n错误原因：数据与ID未匹配\nid：{}", idSet);
            throw new ServiceErrorException("数据异常:ID未配对");
        }
        Map<Integer, Double> idQtyMap = request.stream()
                .collect(Collectors.toMap(AddPurSendRequest::getId,
                        a -> {
                            double sendQty = a.getSendQty() == null ? 0 : a.getSendQty();
                            double overQty = a.getOverQty() == null ? 0 : a.getOverQty();
                            return sendQty + overQty;
                        }));
        Map<Integer, Double> idMinusQtyMap = request.stream()
                .filter(req -> req.getMinusQty() != null)
                .collect(Collectors.toMap(AddPurSendRequest::getId, AddPurSendRequest::getMinusQty));
        Map<Integer, LocalDateTime> idDateMap = request.stream()
                .filter(req -> req.getSendDate() != null)
                .collect(Collectors.toMap(AddPurSendRequest::getId, AddPurSendRequest::getSendDate));
        for (MpPurDis dis : disList) {
            /*处理已入库数量*/
            double inQty = 0;
            LambdaQueryWrapper<PcMtlCheck> checkWrapper = new LambdaQueryWrapper<PcMtlCheck>()
                    .eq(PcMtlCheck::getMtlName, dis.getMtlName())
                    .eq(StringUtils.isNotBlank(dis.getMtlColor()), PcMtlCheck::getMtlColor, dis.getMtlColor())
                    .isNull(StringUtils.isBlank(dis.getMtlColor()), PcMtlCheck::getMtlColor)
                    .eq(StringUtils.isNotBlank(dis.getMtlUnit()), PcMtlCheck::getMtlUnit, dis.getMtlUnit())
                    .isNull(StringUtils.isBlank(dis.getMtlUnit()), PcMtlCheck::getMtlUnit)
                    .eq(StringUtils.isNotBlank(dis.getMtlSpec()), PcMtlCheck::getMtlSpec, dis.getMtlSpec())
                    .isNull(StringUtils.isBlank(dis.getMtlSpec()), PcMtlCheck::getMtlSpec)
                    .eq(PcMtlCheck::getPurNo, dis.getPurNo())
                    .eq(PcMtlCheck::getReqNo, dis.getReqNo())
                    .eq(PcMtlCheck::getPurLot, dis.getLotDetail())
                    .eq(PcMtlCheck::getCompanyId, companyId)
                    .last("LIMIT 1");
            List<PcMtlCheck> checkList = checkMapper.selectList(checkWrapper);
            if (ArrayUtils.isNoEmpyt(checkList)) {
                /*获取已入数量*/
                inQty = checkList.stream()
                        .map(PcMtlCheck::getAcceptQty)
                        .filter(Objects::nonNull)
                        .reduce(BigDecimal.ZERO, BigDecimal::add)
                        .doubleValue();
            }
            float ordQty = dis.getQty() == null ? 0 : dis.getQty();
            float overQty = dis.getOverQty() == null ? 0 : dis.getOverQty();
            if ((idQtyMap.get(dis.getId()) + inQty) > (ordQty + overQty)) {
                log.error("\n错误接口：purSentAdd\n错误原因：暂收正单数量大于订购数量\n暂收数：{}，已收数：{}，采购入库数：{}"
                        , idQtyMap.get(dis.getId()), inQty, dis.getPurQty());
                throw new ServiceErrorException("正单数量超出数量限制");
            }
            /*组装暂收数据*/
            double sendQty = idQtyMap.get(dis.getId());
            LocalDateTime sendDate = idDateMap.get(dis.getId()) == null ? LocalDate.now().atStartOfDay() : idDateMap.get(dis.getId());
            PcMtlCheck sendCheck = BeanUtil.copyBean(dis, PcMtlCheck.class);
            sendCheck.setSendQty(BigDecimal.valueOf(sendQty));
            sendCheck.setSlipType("正单");
            sendCheck.setSendDate(sendDate);
            checks.add(sendCheck);
            /*处理多购数据*/
            Double minusQty = idMinusQtyMap.get(dis.getId());
            if (minusQty != null && minusQty > 0) {
                PcMtlCheck overCheck = BeanUtil.copyBean(dis, PcMtlCheck.class);
                overCheck.setSlipType("多购");
                overCheck.setSendQty(BigDecimal.valueOf(minusQty));
                overCheck.setSendDate(sendDate);
                checks.add(overCheck);
            }
        }
    }

    @Override
    public ResponseInfo sentMtlTypeAdd(List<UserMtlTypeRequest> requests, Integer flag) {
        //MS TODO 2024/7/16 : 解决purNo为空
        /*准备数据*/
        List<PcUserMtlType> mtlTypes = copyList(requests, PcUserMtlType.class);
        mtlTypes.forEach(a -> {
            a.setSysUser(UserIdThread.get().getUserName());
            a.setSysDate(LocalDateTime.now());
        });
        /*选择分类*/
        if (flag.equals(1)) {
            checkMapper.sentMtlTypeAdd(mtlTypes);
        } else {
            checkMapper.sentMtlTypeDelete(mtlTypes);
        }
        return ResponseInfo.ok("修改成功");
    }

    @Override
    public ResponseInfo purPutStockUpdate(List<PurSentRequest> request) {
        String companyId = UserIdThread.get().getCompanyId();
        checkVendorName(request);
        /*复制提取*/
        List<PcMtlCheck> checks = copyList(request, PcMtlCheck.class);
        /*生成自增RecNo*/
        LocalDateTime now = LocalDate.now().atStartOfDay();
        String date = now.format(DateTimeFormatter.ofPattern("yyMM"));
        String key = "PUT_STOCK_" + date;
        RedisAtomicInteger ato = new RedisAtomicInteger(key, redis.getConnectionFactory());
        int increment = ato.getAndIncrement();
        String num = String.format("%0" + PUT_STOCK_LENGTH.getValue() + "d", increment);
        redis.setOutTime(key);
        /*写入入库单号和入库时间*/
        String recNo = null;
        for (PcMtlCheck check : checks) {
            /*判断材料类型*/
            recNo = CompanyEnum.updateId(companyId) + "S" + date + num;
            check.setRecNo(recNo);
            check.setRecDate(now);
        }
        log.info("此次入库的单号为：{}", date + num);
        checkMapper.purPutStockUpdate(checks);
        /*返回结果*/
        return ResponseInfo.ok(recNo);
    }

    /**
     * 判断公司名称是否相同
     */
    private void checkVendorName(List<PurSentRequest> request) {
        Set<String> set = new HashSet<>();
        set.add(request.get(0).getVendorName());
        for (PurSentRequest sentRequest : request) {
            if (set.add(sentRequest.getVendorName())) {
                log.error("存在厂商不相同：vendorName1：{}，vendorName2：{}；\nsendNo1:{}，sendNo2:{}；\npurLot1:{},purLot2:{}",
                        request.get(0).getVendorName(), sentRequest.getVendorName(),
                        request.get(0).getSendNo(), sentRequest.getSendNo(),
                        request.get(0).getPurLot(), sentRequest.getPurLot());
                throw new ServiceErrorException("存在厂商不相同");
            }
        }
    }

    @Override
    @Transactional
    public ResponseInfo purStockUpdate(String recNo) {
        String companyId = UserIdThread.get().getCompanyId();
        /*获取材料数据*/
        List<PcMtlCheck> checks = checkMapper.purStockUpdateQuery(recNo, companyId);
        if (ArrayUtils.isEmpyt(checks)) {
            return ResponseInfo.error("入库单号不存在", DATA_NOT_RETURN.getCode());
        }
        /*判断是否已入库*/
        List<PcMtlCheck> recList = checks.stream().filter(a -> "Y".equals(a.getRecNo())).collect(Collectors.toList());
        if (ArrayUtils.isNoEmpyt(recList)) {
            return ResponseInfo.error("此单已入库,请勿重复操作");
        }
        /*入库*/
        Set<String> mtlNo1 = checks.stream().map(PcMtlCheck::getMtlNo).filter(Objects::nonNull).collect(Collectors.toSet());
        LambdaQueryWrapper<PcMtlAcc> accWrapper = new LambdaQueryWrapper<PcMtlAcc>()
                .eq(PcMtlAcc::getCompanyId, companyId)
                .in(PcMtlAcc::getMtlNo, mtlNo1);
        List<PcMtlAcc> mtlAccs = mtlAccMapper.selectList(accWrapper);
        Set<String> mtlNo2;
        if (ArrayUtils.isNoEmpyt(mtlAccs)) {
            mtlNo2 = mtlAccs.stream().map(PcMtlAcc::getMtlNo).filter(Objects::nonNull).collect(Collectors.toSet());
            List<PcMtlCheck> checks1 = checks.stream().filter(a -> mtlNo2.contains(a.getMtlNo())).collect(Collectors.toList());
            if (ArrayUtils.isNoEmpyt(checks1)) {
                mtlAccMapper.purStockUpdate(checks1, companyId);
            }
        } else {
            mtlNo2 = new HashSet<>();
        }
        /*如果有不存在的数据则新建*/
        if (mtlNo1.size() != mtlNo2.size()) {
            /*找出不存在的部分*/
            Set<String> miss = new HashSet<>(ArrayUtils.findMiss(mtlNo1, mtlNo2));
            List<PcMtlCheck> checks2 = checks.stream().filter(a -> miss.contains(a.getMtlNo())).collect(Collectors.toList());
            List<PcMtlAcc> addMtls = copyList(checks2, PcMtlAcc.class);
            Map<String, BigDecimal> inQtyMap = checks2.stream().collect(Collectors.toMap(PcMtlCheck::getMtlNo, PcMtlCheck::getSendQty));
            /*循环写入*/
            for (PcMtlAcc addMtl : addMtls) {
                BigDecimal inQty = inQtyMap.get(addMtl.getMtlNo());
                addMtl.setCompanyId(companyId);
                addMtl.setRecDate(LocalDateTime.now());
                addMtl.setStockNo("X1");
                addMtl.setInQty(inQty);
                addMtl.setStkQty(inQty);
                mtlAccMapper.insert(addMtl);
            }
        }
        /*更新入库字段*/
        checkMapper.purStockUpdate(recNo);
        return ResponseInfo.ok("入库成功");
    }

    /**
     * 贴合子材料出库
     */
    private void fitSubMtlOut() {

    }

//    @Override
//    public ResponseInfo purUnSentQtyUpdate(List<PurUnSendQtyRequest> request) {
//        /*更新数据*/
//        disMapper.purUnSentQtyUpdate(request);
//        return ResponseInfo.ok("更新成功");
//    }

    @Override
    public ResponseInfo purSentRemark(List<PurSentRemarkRequest> request) {
        /*写入备注数据*/
        checkMapper.purSentRemark(request);
        return ResponseInfo.ok("备注添加成功");
    }

    @Override
    public ResponseInfo purSentDelete(List<PurSentRequest> request) {
        List<PurSentRequest> recList = request.stream().filter(a -> StringUtils.isNotBlank(a.getRecNo())).collect(Collectors.toList());
        /*已有入库单号则无法修改*/
        if (ArrayUtils.isNoEmpyt(recList)) {
            return ResponseInfo.error("已生成入库单号，无法修改", DATA_NOT_RETURN.getCode());
        }
        /*数据删除*/
        checkMapper.purSentDelete(request);
        return ResponseInfo.ok("取消暂收入库成功");
    }

    @Override
    public ResponseInfo purStockBack() {
        String companyId = UserIdThread.get().getCompanyId();
        List<Map<String, String>> vendor = checkMapper.vendorQuery(companyId);
        List<Map<String, String>> mtlType = checkMapper.mtlTypeQuery(UserIdThread.get().getUserName(),companyId);
        Map map = new HashMap();
        map.put("vendor", vendor);
        map.put("mtlType", mtlType);
        return ResponseInfo.ok(map);
    }

    @Override
    @AutoPageAop
    public ResponseInfo getPcMtlCheckFin(PcMtlCheckFinReq req) {
        req.setCompanyId(UserIdThread.get().getCompanyId());
        Map<String, Object> map = new HashMap<>();
        List<PcMtlCheck2> list = checkMapper.getPcMtlCheckFin(req);
        Page<PcMtlCheck2> page = (Page<PcMtlCheck2>) list;
        map.put("total", page.getTotal());
        map.put("list", list);
        return ResponseInfo.ok(map);
    }

    @Override
    public ResponseInfo getPcMtlCheckFinDetail(String recNo) {
        DecimalFormat d1 = new DecimalFormat("0.00000");
        DecimalFormat d2 = new DecimalFormat("0.00");
        DecimalFormat d3 = new DecimalFormat("0.000");
        BigDecimal amtTotal = new BigDecimal(0);
        BigDecimal actTotal = new BigDecimal(0);
        List<PcMtlCheck2> list = checkMapper.getPcMtlCheckFinDetail(recNo, UserIdThread.get().getCompanyId());
        for (PcMtlCheck2 check2 : list) {
            if (check2.getPrice() != null) check2.setPrices(d1.format(check2.getPrice()));
            if (check2.getAmt() != null) check2.setAmts(d3.format(check2.getAmt()));
            BigDecimal amt = check2.getAmt() == null ? new BigDecimal(0) : check2.getAmt();
            amtTotal = amtTotal.add(amt);
            BigDecimal act = check2.getAcceptQty() == null ? new BigDecimal(0) : check2.getAcceptQty();
            actTotal = actTotal.add(act);
        }
        amtTotal = amtTotal.setScale(2, RoundingMode.HALF_UP);
        actTotal = actTotal.setScale(2 , RoundingMode.HALF_UP);
        Map<String, Object> map = new HashMap<>();
        map.put("amtTotal", d2.format(amtTotal));
        map.put("actTotal", d2.format(actTotal));
        map.put("list", list);
        return ResponseInfo.ok(map);
    }

    @Override
    public ResponseInfo getSdBomFitSub(String mtlNo) {
        List<SdBomFitSub> list = checkMapper.getSdBomFitSub(mtlNo, UserIdThread.get().getCompanyId());
        return ResponseInfo.ok(list);
    }

    @Override
    public ResponseInfo optionPcMtlCheck(List<PcMtlCheck2> list, String choose) {
        for (PcMtlCheck2 pcMtlCheck2 : list) {
            List<PcMtlCheck2> lists = checkMapper.getPcMtlCheckFinDetail(pcMtlCheck2.getRecNo(), UserIdThread.get().getCompanyId());
            for (PcMtlCheck2 mtlCheck2 : lists) {
                if ("2".equals(choose)) {
                    if(!UserIdThread.get().getUserName().equals(mtlCheck2.getCfmUser())) throw new ServiceErrorException("不可取消检核，请确认是否为检核人");
                }
                if(ZStringUtils.isNotEmpty(mtlCheck2.getFinanceCfmFlag())) throw new ServiceErrorException("财务对账，无法修改");
//                if (mtlCheck2.getPrice() == null) return ResponseInfo.error("单价不能为空");
            }
        }
        checkMapper.optionPcMtlCheck(list, choose, UserIdThread.get());
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo clickPcMtlCheck(List<PcMtlCheck2> list, String remark) {
        for (PcMtlCheck2 pcMtlCheck2 : list) {
            String str = checkMapper.getListByRecNo(pcMtlCheck2);
            if (str == null || "".equals(str)) {
                checkMapper.insertIntoRemark2(pcMtlCheck2, remark);
            } else {
                checkMapper.updateRemark2(pcMtlCheck2, remark);
            }
        }
        checkMapper.clickPcMtlCheck(list, remark);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo savePcMtlCheck(List<PcMtlCheck2> list) {
        DecimalFormat d1 = new DecimalFormat("0.00000");
        for (PcMtlCheck2 pcMtlCheck2 : list) {
            BigDecimal price = pcMtlCheck2.getPrice();
            BigDecimal qty = pcMtlCheck2.getAcceptQty();
            if (price != null && qty != null) {
                BigDecimal amt = price.multiply(qty); //金额
                pcMtlCheck2.setAmts(d1.format(amt));
            }
        }
        checkMapper.savePcMtlCheck(list);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo getDetails() {
        List<String> list = checkMapper.getDetails();
        return ResponseInfo.ok(list);
    }

    @Override
    @AutoPageAop
    public ResponseInfo getSurfaceMtl(SurfaceInMaterialReq req) {
        Map<String, Object> map = new HashMap<>();
        req.setCompanyId(UserIdThread.get().getCompanyId());
        List<PcMtlCheck2> list = checkMapper.getSurfaceMtl(req);
        BigDecimal acceptTotal = checkMapper.getAcceptTotal(req);
        BigDecimal amtTotal = checkMapper.getAmtTotal(req);
        Page<PcMtlCheck2> page = (Page<PcMtlCheck2>) list;
        map.put("total", page.getTotal());
        map.put("list", list);
        map.put("acceptTotal", acceptTotal);
        map.put("amtTotal", amtTotal);
        return ResponseInfo.ok(map);
    }

    @Override
    public ResponseInfo getUnitPrice(List<PcMtlCheck2> list) {
        Integer i = 0;
        for (PcMtlCheck2 pcMtlCheck2 : list) {
            if (pcMtlCheck2.getPrice() != null && pcMtlCheck2.getPrice().doubleValue() > 0) continue;
            pcMtlCheck2.setCompanyId(UserIdThread.get().getCompanyId());
            BigDecimal unitPrice = checkMapper.getUnitPrice(pcMtlCheck2);
            if (unitPrice != null) i++;
            unitPrice = unitPrice == null ? new BigDecimal(0) : unitPrice;
            BigDecimal acceptQty = pcMtlCheck2.getAcceptQty() == null ? new BigDecimal(0) : pcMtlCheck2.getAcceptQty();
            BigDecimal amt = acceptQty.multiply(unitPrice, MathContext.DECIMAL32);
            if (amt.doubleValue() > 0) pcMtlCheck2.setAmts(String.valueOf(amt));
            if (unitPrice.doubleValue() > 0) pcMtlCheck2.setPrices(String.valueOf(unitPrice));

        }
        checkMapper.savePcMtlCheck(list);
        return ResponseInfo.ok(i);
    }

    private final PcLotHeadMapper lotHeadMapper;
    private final SD_SQ_SdBomMtlMapper bomMtlMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void mtlInvCount(List<MtlAccVo> read) {
        String companyId = UserIdThread.get().getCompanyId();
        // 1.指令筛选
        List<String> lotNoList = read.stream().map(MtlAccVo::getLotNo).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        LambdaQueryWrapper<PcLotHead> lotWrapper = new LambdaQueryWrapper<PcLotHead>()
                .select(PcLotHead::getLotNo)
                .in(PcLotHead::getLotNo, lotNoList);
        List<PcLotHead> lotHeadList = lotHeadMapper.selectList(lotWrapper);
        Set<String> existLotSet;
        if (ArrayUtils.isNoEmpyt(lotHeadList)) {
            existLotSet = lotHeadList.stream().map(PcLotHead::getLotNo).collect(Collectors.toSet());
        } else {
            existLotSet = new HashSet<>();
        }
        List<MtlAccVo> unExistRead = read.stream().filter(a -> !existLotSet.contains(a.getLotNo())).collect(Collectors.toList());

        // 2.导入库存数据
        List<PcMtlAcc> accList = new ArrayList<>();
        for (MtlAccVo vo : unExistRead) {
            PcMtlAcc acc = new PcMtlAcc()
                    .setMtlUnit(vo.getMtlUnit())
                    .setInQty(vo.getStkQty2() == null ? vo.getStkQty() : vo.getStkQty2())
                    .setCompanyId(companyId);
            String[] split = vo.getMtlName().split("、");
            if (split.length == 2) {
                acc.setMtlColor(split[0])
                        .setMtlName(split[1]);
            } else if (split.length == 3) {
                acc.setMtlColor(split[0])
                        .setMtlSpec(split[1])
                        .setMtlName(split[2]);
            } else {
                continue;
            }
            /*补充包含物料编号的数据*/
            PcMtlAcc findAcc = bomMtlMapper.getMissByVo(acc);
            if (findAcc == null){
                log.error("\n错误接口：mtlInvCount\n错误原因：{}",acc);
                throw new ServiceErrorException("物料异常");
            }
            /*存在判断*/
            Integer count = mtlAccMapper.existCheck(findAcc);
            /*补录库存*/
            if (count == 0) {
                mtlAccMapper.insert(acc);
            }else {
                mtlAccMapper.stkUpByMtl(acc);
            }
        }

    }

    @Override
    public void mtlAccIn(List<PcMtlAcc> accList) {
        String companyId = UserIdThread.get().getCompanyId();
        accList.forEach(a -> {
            /*数据补全*/
            LocalDateTime recDate = a.getRecDate() == null ? LocalDateTime.now() : a.getRecDate();
            a.setCompanyId(companyId);
            a.setRecDate(recDate);
        });
        /*找出已经存在的物料ID*/
        Set<String> mtlNoSet = accList.stream()
                .map(PcMtlAcc::getMtlNo)
                .collect(Collectors.toSet());
        LambdaQueryWrapper<PcMtlAcc> accWrapper = new LambdaQueryWrapper<PcMtlAcc>()
                .select(PcMtlAcc::getMtlNo)
                .eq(PcMtlAcc::getMtlNo, mtlNoSet)
                .eq(PcMtlAcc::getCompanyId, companyId);
        List<PcMtlAcc> mtlAccs = mtlAccMapper.selectList(accWrapper);
        /*结果存储*/
        List<PcMtlAcc> insMtlList = new ArrayList<>(accList);
        if (ArrayUtils.isNoEmpyt(mtlAccs)) {
            Set<String> findMtlNoSet = mtlAccs.stream().map(PcMtlAcc::getMtlNo).collect(Collectors.toSet());
            /*遍历 mtlQtyMap 进行分类*/
            for (PcMtlAcc mtlAcc : accList) {
                if (!findMtlNoSet.contains(mtlAcc.getMtlNo())) {
                    insMtlList.add(mtlAcc);
                }
            }
        } else {
            insMtlList.addAll(accList);
        }
        /*根据mtlNo去重*/
        List<PcMtlAcc> uniqueInsMtlList = insMtlList.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toMap(
                                PcMtlAcc::getMtlNo,
                                insMtl -> insMtl,
                                /*如果遇到重复的 mtlNo，则保留现有的元素*/
                                (existing, replacement) -> existing
                        ),
                        map -> new ArrayList<>(map.values())
                ));
        mtlAccMapper.mtlAccBaseIn(uniqueInsMtlList);
        /*更新库存数据*/
        Map<String, BigDecimal> mtlInMap = accList.stream()
                .collect(Collectors.toMap(PcMtlAcc::getMtlNo, PcMtlAcc::getInQty, BigDecimal::add));
        mtlAccMapper.stkInByMap(mtlInMap, companyId);
    }

    @Override
    public void purSendUpdate(Integer id, LocalDateTime sendDate, String sendNo, String remark) {
        String y = "Y";
        SysUserTokenDTO tokenDTO = UserIdThread.get();
        String companyId = tokenDTO.getCompanyId();
        String userName = tokenDTO.getUserName();
        /*判断是否为本人数据*/
        PcMtlCheck check = checkMapper.selectById(id);
        if (!userName.equals(check.getSysUser()) || !companyId.equals(check.getCompanyId())) {
            throw new RuntimeException("无法修改非本人数据");
        }

        /*已入库不能修改*/
        if (y.equals(check.getRecFlag())) {
            throw new RuntimeException("已入库不能修改");
        }

        /*更新数据*/
        PcMtlCheck newCheck = new PcMtlCheck()
                .setPrimaryId(id)
                .setSendDate(sendDate)
                .setSendNo(sendNo)
                .setRemark(remark);
        checkMapper.updateById(newCheck);
    }

    @Override
    public void purSpSentDelete(String primaryId, int slipType) {
        SysUserTokenDTO tokenDTO = UserIdThread.get();
        /*判断数据是否满足修改条件*/
        PcMtlCheck check = checkMapper.selectById(primaryId);
        if (!tokenDTO.getCompanyId().equals(check.getCompanyId())) {
            log.error("\n错误接口：purSpSentDelete\n错误原因：修改非本公司数据");
            throw new ServiceErrorException("数据异常");
        }
        if (!tokenDTO.getUserName().equals(check.getSysUser())) {
            throw new ServiceErrorException("无法修改非本人数据");
        }
        if (StringUtils.isNotBlank(check.getRecNo())) {
            throw new ServiceErrorException("已生成入库单号，无法修改");
        }
        /*删除待入库数据*/
        checkMapper.deleteById(primaryId);
    }

    @Override
    public void printMiss(List<MtlAccVo> read, HttpServletResponse response) {
        String companyId = UserIdThread.get().getCompanyId();
        // 1.指令筛选
        List<String> lotNoList = read.stream().map(MtlAccVo::getLotNo).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        LambdaQueryWrapper<PcLotHead> lotWrapper = new LambdaQueryWrapper<PcLotHead>()
                .select(PcLotHead::getLotNo)
                .in(PcLotHead::getLotNo, lotNoList)
                .ge(PcLotHead::getSysDate, "2024-10-01");
        List<PcLotHead> lotHeadList = lotHeadMapper.selectList(lotWrapper);
        Set<String> existLotSet;
        if (ArrayUtils.isNoEmpyt(lotHeadList)) {
            existLotSet = lotHeadList.stream().map(PcLotHead::getLotNo).collect(Collectors.toSet());
        } else {
            existLotSet = new HashSet<>();
        }
        List<MtlAccVo> unExistRead = read.stream().filter(a -> !existLotSet.contains(a.getLotNo())).collect(Collectors.toList());
        // 2.导入库存数据
        List<PcMtlAcc> accList = new ArrayList<>();
        for (MtlAccVo vo : unExistRead) {
            PcMtlAcc acc = new PcMtlAcc()
                    .setMtlUnit(vo.getMtlUnit())
//                    .setInQty(vo.getStkQty2() == null ? vo.getStkQty() : vo.getStkQty2())
                    .setCompanyId(companyId);
            String[] split = vo.getMtlName().split("、");
            if (split.length == 2) {
                acc.setMtlColor(split[0])
                        .setMtlName(split[1]);
            } else if (split.length == 3) {
                acc.setMtlColor(split[0])
                        .setMtlSpec(split[1])
                        .setMtlName(split[2]);
            } else {
                System.out.println(vo.getMtlName());
            }
            accList.add(acc);
        }
        // 找出未建档数据
        List<PcMtlAcc> missAccList = new ArrayList<>();
        for (PcMtlAcc mtlAcc : accList) {
            PcMtlAcc missAcc = bomMtlMapper.getMissByVo(mtlAcc);
            if (missAcc != null) {
                missAccList.add(missAcc);
            }
        }
        if (ArrayUtils.isNoEmpyt(missAccList)) {
            accList = accList.stream()
                    .filter(acc -> missAccList.stream().noneMatch(missAcc ->
                            acc.getMtlName().replace(" ", "").equals(missAcc.getMtlName().replace(" ", "")) &&
                                    acc.getMtlColor().replace(" ", "").equals(missAcc.getMtlColor().replace(" ", "")) &&
                                    acc.getMtlUnit().replace(" ", "").equals(missAcc.getMtlUnit().replace(" ", "")) &&
                                    (acc.getMtlSpec() == null || acc.getMtlSpec().isEmpty() ||
                                            acc.getMtlSpec().replace(" ", "").equals(missAcc.getMtlSpec() != null ? missAcc.getMtlSpec().replace(" ", "") : ""))
                    )).collect(Collectors.toList());
        }

        // 导出
        try {
            ExcelUtils.autoWidth(1).creatByTemplate(response, "miss.xlsx", "未建档数据", accList);
        } catch (IOException e) {
            throw new ServiceErrorException(e.getMessage());
        }
    }


    /**
     * 根据规则分割字符串
     *
     * @param input 输入字符串
     * @return 分割后的字符串列表
     */
    public static List<String> splitString(String input) {
        if (StringUtil.isBlank(input)) {
            return new ArrayList<>();
        }
        // 去除空格
        String cleanedInput = input.replaceAll("\\s+", "");

        // 初始化分割结果数组
        String[] parts = new String[3];
        int splitCount = 0;

        // 第一次分隔符切割
        int firstDashIndex = cleanedInput.indexOf('-');
        if (firstDashIndex != -1) {
            char beforeFirstDash = cleanedInput.charAt(firstDashIndex - 1);
            char afterFirstDash = cleanedInput.charAt(firstDashIndex + 1);

            if (Character.isDigit(beforeFirstDash) && Character.isDigit(afterFirstDash)) {
                // 如果第一个 '-' 符号前后都是数字，视为一个整体
                int nextDashIndex = cleanedInput.indexOf('-', firstDashIndex + 1);
                if (nextDashIndex == -1) {
                    parts[splitCount++] = cleanedInput;
                } else {
                    parts[splitCount++] = cleanedInput.substring(0, nextDashIndex);
                    cleanedInput = cleanedInput.substring(nextDashIndex + 1);
                }
            } else {
                // 否则，在第一个 '-' 符号处分割
                parts[splitCount++] = cleanedInput.substring(0, firstDashIndex);
                cleanedInput = cleanedInput.substring(firstDashIndex + 1);
            }
        }
        // 第二次分隔符切割
        int secondDashIndex = cleanedInput.indexOf('-');
        if (secondDashIndex != -1 && splitCount < 2) {
            String beforeSecondDash = cleanedInput.substring(secondDashIndex - 2, secondDashIndex);
            if ("MM".equals(beforeSecondDash)) {
                // 如果第二个 '-' 符号前的部分是 "MM"，进行分割
                parts[splitCount++] = cleanedInput.substring(0, secondDashIndex); // 提取 "1.0MM"
                parts[splitCount++] = cleanedInput.substring(secondDashIndex + 1);
            } else {
                // 如果第二个 '-' 符号前的部分不是 "MM"，视为一个整体
                parts[splitCount++] = cleanedInput;
            }
        } else {
            // 如果没有第二个 '-' 符号，剩余部分视为一个整体
            parts[splitCount++] = cleanedInput;
        }

        // 修剪数组到实际分割的数量
        String[] result = new String[splitCount];
        System.arraycopy(parts, 0, result, 0, splitCount);
        return Arrays.asList(result);
    }
}
